package es.unileon.rnag.jgen;
import java.lang.reflect.InvocationTargetException;
import es.unileon.rnag.jgen.genes.*;
/**
 * Clase abstracta base para los cromosomas
 * @author Abel Mayorga Gonz&aacute;lez
 * @author Sergio Fern&aacute;ndez Mart&iacute;nez
 * @version 1.0
 */

public abstract class Cromosoma {
	//Array de genes
	private Gen[] _genes;
	//Numero maximo de genes
	private int _maxGenes;
	//Numero de genes
	private int _nGenes;
	
	/**
	 * Constructor de copia
	 * @param c: Cromosoma a copiar
	 */
	public Cromosoma(Cromosoma c){
		Gen[] genes = c.getGenes();
		_maxGenes = genes.length;
		_genes = new Gen[_maxGenes];
		//Clona los genes
		for(int i = 0; i < _maxGenes; i++){
			_genes[i] = genes[i].clonar();
		}
		_nGenes = _maxGenes;
	}
	
	/**
	 * Clona el cromosoma actual
	 * @return: El cromosoma clonado
	 */
	public Cromosoma clonar(){
		//Guarda la clase Cromosoma en un array de argumentos
		Class[] args = new Class[] {Cromosoma.class};
		try {
			//Obtiene el constructor de esta clase que recibe los argumentos indicados y crea una nueva instancia
			return this.getClass().getConstructor(args).newInstance(this);
		} catch (Exception e){
			e.printStackTrace();
			throw new RuntimeException(e);//Se lanza esta excepcion para que termine el programa
		}
	}
	
	/**
	 * Establece el n&uacute;mero de genes de los que contar&aacute; este cromosoma
	 * @param nGenes: N&uacute;mero de genes para el cromosoma actual.
	 */
	protected Cromosoma(int nGenes){
		_maxGenes = nGenes;
		_genes = new Gen[_maxGenes];
		_nGenes = 0;
	};
	
	/**
	 * A&ntilde;ade un gen al cromosoma actual
	 * @param gen: Gen a a&ntilde;adir
	 * @return true si se puede a&ntilde;adir, false de lo contrario
	 */
	public boolean addGen(Gen gen){
		if(_nGenes<_maxGenes){
			_genes[_nGenes] = gen;
			_nGenes++;
			return true;
		}
		return false;
	}
	
	/**
	 * Calcula la aptitud del cromosoma actual
	 * @return La aptitud del cromosoma actual
	 */
	protected abstract double calcularAptitud();
	
	/**
	 * Devuelve la aptitud del cromosoma actual
	 * @return La aptitud del cromoosma actual
	 */
	public final double getAptitud(){
		return calcularAptitud();
	}
	
	/**
	 * Obtiene el array de genes del cromosoma actual
	 * @return El array de genes del cromosoma actual
	 */
	public final Gen[] getGenes(){
		return _genes;
	}
	
	/**
	 * Obtiene la cadena de bits que representa a este cromosoma
	 * @return La cadena de bits que representa a este cromosoma
	 */
	public final String getBitString(){
		String cadena = "";
		for(int i = 0; i < _genes.length; i++){
			cadena = cadena.concat(_genes[i].getBitString());
		}
		return cadena;
	}
	
}
